package me.boot.web.common.template.controller;

import cn.afterturn.easypoi.entity.vo.NormalExcelConstants;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.ExcelXorHtmlUtil;
import cn.afterturn.easypoi.excel.entity.ExcelToHtmlParams;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.view.PoiBaseView;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.google.common.collect.Maps;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import me.boot.db.mybatis.template.SuperService;
import me.boot.db.mybatis.template.entity.Entity;
import me.boot.web.common.template.model.PageParam;
import me.boot.web.common.template.model.Result;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.List;
import java.util.Map;

public interface PoiController<
        ID extends Serializable,
        PO extends Entity<ID>,
        S extends SuperService<ID, PO>,
        DTO>
        extends PageController<ID, PO, S, DTO> {


    /**
     * 导出Excel
     *
     * @param param    参数
     * @param request  请求
     * @param response 响应
     */
    @ApiOperation(value = "导出Excel")
    @ApiOperationSupport(order = 51)
    @PostMapping(value = "/excel/export", produces = "application/octet-stream")
    default void export(@RequestBody @Validated PageParam<DTO> param, HttpServletRequest request, HttpServletResponse response) {
        IPage<PO> page = pageQuery(param);
        ExportParams exportParams = getExportParams(param);

        Map<String, Object> map = Maps.newHashMap();
        map.put(NormalExcelConstants.DATA_LIST, page.getRecords());
        map.put(NormalExcelConstants.CLASS, getPoClass());
        map.put(NormalExcelConstants.PARAMS, exportParams);
        Object fileName = param.getExtra().getOrDefault(NormalExcelConstants.FILE_NAME, "tmpExcel");
        map.put(NormalExcelConstants.FILE_NAME, fileName);
        PoiBaseView.render(map, request, response, NormalExcelConstants.EASYPOI_EXCEL_VIEW);
    }

    /**
     * 预览Excel
     *
     * @param params 预览参数
     */
    @SneakyThrows
    @ApiOperation(value = "预览Excel")
    @ApiOperationSupport(order = 52)
    @RequestMapping(value = "/excel/preview", method = RequestMethod.POST)
    default void preview(@RequestBody @Validated PageParam<DTO> params, HttpServletResponse response) {
        IPage<PO> page = pageQuery(params);
        ExportParams exportParams = getExportParams(params);

        try (Workbook workbook = ExcelExportUtil.exportExcel(exportParams, getPoClass(), page.getRecords())) {
            String html = ExcelXorHtmlUtil.excelToHtml(new ExcelToHtmlParams(workbook));
            response.getOutputStream().write(html.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 使用自动生成的实体+注解方式导入 对RemoteData 类型的字段不支持，
     * 建议自建实体使用
     *
     * @param simpleFile 上传文件
     * @param request    请求
     * @param response   响应
     * @return 是否导入成功
     * @throws Exception 异常
     */
    @ApiOperation(value = "导入Excel")
    @ApiOperationSupport(order = 53)
    @PostMapping(value = "/excel/import")
    default Result<Boolean> importExcel(@RequestParam(value = "file") MultipartFile simpleFile,
                                        HttpServletRequest request,
                                        HttpServletResponse response) throws Exception {
        String strTitleRows = request.getParameter("titleRows");
        String strHeadRows = request.getParameter("headRows");
        int titleRows = StrUtil.isEmpty(strTitleRows) ? 0 : Convert.toInt(strTitleRows);
        int headRows = StrUtil.isEmpty(strHeadRows) ? 0 : Convert.toInt(strHeadRows);

        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headRows);

        List<Map<String, String>> list = ExcelImportUtil.importExcel(simpleFile.getInputStream(), Map.class, params);

        if (list == null || list.isEmpty()) {
            return Result.newFaild("导入Excel,无有效数据！");
        }

        processImportData(list);
        return Result.newSuccess(true);
    }


    /**
     * 处理导入数据
     *
     * @param list 处理后的Excel数据
     */
    default void processImportData(List<Map<String, String>> list) {
        //子类须重载导入逻辑
    }


    /**
     * 构建导出参数
     *
     * @param params 分页参数
     * @return 导出参数
     */
    default ExportParams getExportParams(PageParam<DTO> params) {
        Object title = params.getExtra().getOrDefault("title", "【文档标题】");
        Object type = params.getExtra().getOrDefault("type", ExcelType.XSSF.name());
        Object sheetName = params.getExtra().getOrDefault("sheetName", "sheet1");
        ExcelType excelType = ExcelType.XSSF.name().equals(type) ? ExcelType.XSSF : ExcelType.HSSF;
        return new ExportParams(String.valueOf(title), sheetName.toString(), excelType);
    }
}
